<template>
  <div class="permission-management">
    <el-row style="margin-bottom:20px">
      <el-col :span="2">
        <h2>权限管理</h2>
      </el-col>
      <el-col :span="2">
        <el-button size="medium" type="primary" @click="savePermissions">保存</el-button>
      </el-col>
    </el-row>
    <el-row>
      <el-col :span="6">
        <h3>角色列表</h3>
        <el-tree
          :data="roles"
          node-key="id"
          :props="defaultProps"
          @node-click="handleRoleClick"
          :default-expand-all="true"
          highlight-current
          ref="roleTree"
          class="tree-with-border"
        ></el-tree>
      </el-col>
      <el-col :span="8">
        <h3>已分配权限</h3>
        <el-tree
          ref="assignedTree"
          :data="assignedPermissions"
          node-key="id"
          :props="defaultProps"
          show-checkbox
          :default-expand-all="true"
          class="tree-with-border"
        ></el-tree>
      </el-col>
      <el-col :span="2">
        <h3>操作</h3>
        <div class="button-group">
          <el-button size="small" @click="assignSelected">&lt;</el-button>
          <el-button size="small" @click="assignAll">&lt;&lt;</el-button>
          <el-button size="small" @click="unassignSelected">&gt;</el-button>
          <el-button size="small" @click="unassignAll">&gt;&gt;</el-button>
        </div>
      </el-col>
      <el-col :span="8">
        <h3>未分配权限</h3>
        <el-tree
          ref="unassignedTree"
          :data="unassignedPermissions"
          node-key="id"
          :props="defaultProps"
          show-checkbox
          :default-expand-all="true"
          class="tree-with-border"
        ></el-tree>
      </el-col>
    </el-row>
  </div>
</template>

<script>
export default {
  data() {
    return {
      roles: [],
      permissions: [],
      assignedPermissions: [],
      unassignedPermissions: [],
      selectedRole: null,
      defaultProps: {
        children: "children",
        label: "name"
      }
    };
  },
  created() {
    this.fetchRoles();
    this.fetchPermissions();
  },
  methods: {
    fetchRoles() {
      this.$axios.get("/roles").then(response => {
        this.roles = response.data.data;
      });
    },
    fetchPermissions() {
      this.$axios.get("/permissions").then(response => {
        const permissions = response.data.data;
        this.permissions = this.buildTree(permissions);
      });
    },
    handleRoleClick(role) {
      this.selectedRole = role;
      this.$refs.roleTree.setCurrentKey(role.id);
      this.fetchRolePermissions(role.id);
    },
    fetchRolePermissions(roleId) {
      this.$axios.get(`/roles/${roleId}/permissions`).then(response => {
        const assignedPermissions = response.data.data;
        this.assignedPermissions = this.buildTree(assignedPermissions);
        this.unassignedPermissions = this.permissions.filter(
          p => !this.assignedPermissions.some(ap => ap.id === p.id)
        );
      });
    },
    assignSelected() {
      const selectedNodes = this.$refs.unassignedTree.getCheckedNodes();
      this.moveNodes(
        selectedNodes,
        this.unassignedPermissions,
        this.assignedPermissions
      );
      this.clearIndeterminateState(this.$refs.unassignedTree);
    },
    assignAll() {
      this.moveNodes(
        this.unassignedPermissions,
        this.unassignedPermissions,
        this.assignedPermissions
      );
      this.clearIndeterminateState(this.$refs.unassignedTree);
    },
    unassignSelected() {
      const selectedNodes = this.$refs.assignedTree.getCheckedNodes();
      this.moveNodes(
        selectedNodes,
        this.assignedPermissions,
        this.unassignedPermissions
      );
      this.clearIndeterminateState(this.$refs.assignedTree);
    },
    unassignAll() {
      this.moveNodes(
        this.assignedPermissions,
        this.assignedPermissions,
        this.unassignedPermissions
      );
      this.clearIndeterminateState(this.$refs.assignedTree);
    },
    moveNodes(nodes, from, to) {
      nodes.forEach(node => {
        const parentNode = this.findParentNode(node, from);
        if (parentNode) {
          const index = parentNode.children.findIndex(
            item => item.id === node.id
          );
          if (index !== -1) {
            const [movedNode] = parentNode.children.splice(index, 1);
            this.addNodeToTree(movedNode, to, parentNode);
            if (parentNode.children.length === 0) {
              const parentIndex = from.findIndex(
                item => item.id === parentNode.id
              );
              if (parentIndex !== -1) {
                from.splice(parentIndex, 1);
              }
            }
          }
        } else {
          const index = from.findIndex(item => item.id === node.id);
          if (index !== -1) {
            const [movedNode] = from.splice(index, 1);
            this.addNodeToTree(movedNode, to);
          }
        }
      });
    },
    findParentNode(node, tree) {
      for (const item of tree) {
        if (
          item.children &&
          item.children.some(child => child.id === node.id)
        ) {
          return item;
        }
        if (item.children) {
          const parent = this.findParentNode(node, item.children);
          if (parent) {
            return parent;
          }
        }
      }
      return null;
    },
    addNodeToTree(node, tree, parentNode = null) {
      if (parentNode) {
        let existingParent = tree.find(item => item.id === parentNode.id);
        if (!existingParent) {
          existingParent = { ...parentNode, children: [] };
          tree.push(existingParent);
        }
        existingParent.children.push(node);
      } else {
        let existingNode = tree.find(item => item.id === node.id);
        if (!existingNode) {
          tree.push(node);
        } else {
          existingNode.children = [
            ...(existingNode.children || []),
            ...(node.children || [])
          ];
        }
      }
    },
    clearIndeterminateState(tree) {
      Object.values(tree.store.nodesMap).forEach(node => {
        if (node.indeterminate) {
          node.setChecked(false, false);
        }
      });
    },
    buildTree(data) {
      const tree = [];
      const map = {};
      data.forEach(item => {
        map[item.id] = { ...item, children: [] };
      });
      data.forEach(item => {
        if (item.parentId) {
          map[item.parentId].children.push(map[item.id]);
        } else {
          tree.push(map[item.id]);
        }
      });
      return tree;
    },
    savePermissions() {
      const permissionIds = this.assignedPermissions.flatMap(this.flattenTree);
      this.$axios
        .post(`/roles/${this.selectedRole.id}/permissions`, permissionIds)
        .then(() => {
          this.$message.success("权限保存成功！请刷新页面查看最新权限");
        });
    },
    flattenTree(node) {
      return [node.id, ...node.children.flatMap(this.flattenTree)];
    }
  }
};
</script>

<style scoped>
.permission-management {
  display: flex;
  flex-direction: column;
  padding: 20px;
}

.tree-with-border {
  border: 1px solid #dcdfe6;
  padding: 10px;
  height: 400px;
}

.button-group {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin: 0;
  border: 1px solid #dcdfe6;
  padding: 10px;
  height: 400px;
}

.button-group .el-button {
  margin: 5px 0;
  width: 50px;
}

.save-button {
  text-align: center;
  margin-top: 20px;
}
</style>